
#include "common/mscommon.h"
#include "mem/dram/ideal/ideal.hh"

#include "util/algorithm.hh"

namespace MsCtrl::Memory::DRAM {

IdealDRAM::IdealDRAM(ObjectData &o)
    : AbstractDRAM(o),
      scheduler(
          o, "Memory::IdealDRAM::scheduler",
          [this](Request *r) -> uint64_t { return preSubmit(r); },
          [this](Request *r) { postDone(r); }, Request::backup,
          Request::restore) {
  // Latency of transfer (MemoryPacketSize)
  auto bytesPerClock = 2.0 * pStructure->channel * pStructure->width *
                       pStructure->chip / 8.0 / pTiming->tCK;  // bytes / ps
  packetLatency = MemoryPacketSize / bytesPerClock;
}

IdealDRAM::~IdealDRAM() {
}

uint64_t IdealDRAM::preSubmit(Request *req) {
  uint64_t cycle = getTick() / pTiming->tCK;

  UNUSED(req);

  updateStats(cycle);

  return packetLatency;
}

void IdealDRAM::postDone(Request *req) {
  scheduleNow(req->eid, req->data);

  delete req;
}

void IdealDRAM::read(uint64_t address, Event eid, uint64_t data) {
  auto req = new Request(true, address, eid, data);

  // Enqueue request
  req->beginAt = getTick();

  readStat.add(MemoryPacketSize);

  scheduler.enqueue(req);
}

void IdealDRAM::write(uint64_t address, Event eid, uint64_t data) {
  auto req = new Request(false, address, eid, data);

  // Enqueue request
  req->beginAt = getTick();

  writeStat.add(MemoryPacketSize);

  scheduler.enqueue(req);
}

void IdealDRAM::createCheckpoint(std::ostream &out) const noexcept {
  AbstractDRAM::createCheckpoint(out);

  BACKUP_SCALAR(out, packetLatency);

  scheduler.createCheckpoint(out);
}

void IdealDRAM::restoreCheckpoint(std::istream &in) noexcept {
  AbstractDRAM::restoreCheckpoint(in);

  RESTORE_SCALAR(in, packetLatency);

  scheduler.restoreCheckpoint(in);
}

void IdealDRAM::getStatList(std::vector<Stat> &list,
                            std::string prefix) noexcept {
  AbstractDRAM::getStatList(list, prefix);
}

void IdealDRAM::getStatValues(std::vector<double> &values) noexcept {
  AbstractDRAM::getStatValues(values);
}

void IdealDRAM::resetStatValues() noexcept {
  AbstractDRAM::resetStatValues();
}

void IdealDRAM::updateStats(uint64_t cycle) noexcept {
  UNUSED(cycle);
}

}  // namespace MsCtrl::Memory::DRAM
